import base64
import pickle

from django import http
import json

from django_redis import get_redis_connection

from apps.goods.models import SKU
from utils.response_code import RETCODE
from django.shortcuts import render
from django.views import View
"""
分析:
    方向一: 通过经验
    方向二: 看别的网站的类似的效果


需求:

   1. 未登录用户可以实现购物车的添加,也能够保存数据

        登陆用户可以实现购物车的添加

    2.未登录用户保存在哪里  浏览器 (cookie中)

        登录用户保存在哪里  服务器  数据库中
                                Redis(课程设计,真实实现)

    3. 未登录用户保存 商品id,商品数量,勾选状态
        cookie:
        key:value
        carts: { sku_id: {count:xxx,selected:True} }


        carts: {
                    1:{count:5,selected:True},
                    3:{count:15,selected:False},
                }
                (购物车要求顺序，可以用列表或有序字典)

        登录用户保存 用户id,商品id,商品数量,勾选状态

            数据库 user_id,sku_id,count,selected

                     1      1       5   1
                     1      3       15  0
                     333    1       1   1
                     333    2       1   0



            Redis(课程设计,真实实现)
            Redis是保存在内存中,我们的原则是:尽量少的占用内存空间 (先实现功能)

                 user_id,sku_id,count,selected



            Hash
                user_id:
                        sku_id:count,
                        sku_id:count,

                1:
                  1:10


                  2:20


                2:
                  1:10


                  2:20
            Set
                user_id: [sku_id,sku_id] 选中的商品的id

                1:  [1]

                2:


    4. 对cookie数据进行加密处理

        1G=1024MB
        1M=1024KB
        1KB=1024B
        1B=8bytes

        1字节=8b
        b: 0/1

        A       0100    0001

        A   A   A
        0100    0001    0100    0001    0100    0001

        X   y z s
        010000      010100    000101    000001


"""

"""
    添加购物车的思路

        需求:
            当用户点击加入购物车的时候,需要让前端收集  sku_id,count,selected(可以不提交默认是True)
            因为请求的时候会携带用户信息(如果用户登陆)
        后端:

            # 1.后端接收数据
            # 2.验证数据
            # 3.判断用户登陆状态
            # 4.登陆用户保存在redis
            #     4.1 连接redis
            #     4.2 hash
            #         set
            #     4.3 返回
            # 5.未登录用户保存在cookie中
            #     5.1 组织数据
            #     5.2 加密
            #     5.3 设置cookie
            #     5.4 返回相应

        路由和请求方式
            POST        carts
    """
class CartsView(View):
    # 添加购物车
    def post(self,request):
        # 1.后端接收数据
        data = json.loads(request.body.decode())
        # 2.验证数据
        sku_id=data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected',True)
        # 2.1商品ｉｄ和个数必须传递
        if not all([sku_id,count]):
            return  http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数不全'})
        # 2.2判断商品是否存在
        try:
            sku=SKU.objects.get(pk=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({'code':RETCODE.NODATAERR,'errmsg':'没有此商品'})
        # 2.3判断商品个数是否为整形
        try:
            count=int(count)
        except Exception as e:
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数错误'})
        # 2.4判断选中状态是否为布尔值
        if not isinstance(selected,bool):
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数错误'})
        # 3.判断用户登陆状态
        user= request.user
        if user.is_authenticated:

            # 4.登陆用户保存在redis
            #     4.1 连接redis
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            #     4.2 hash
            # carts_userid:
            #   sku_id:count
            # redis_conn.hset(key,field,value)
            # redis_conn.hset('carts_%s' % user.id, sku_id, count)
            # 新增购物车数据
            pl.hincrby('carts_%s' % user.id, sku_id, count)
            # 新增选中的状态
            if selected:
                pl.sadd('selected_%s' % user.id, sku_id)
            # 执行管道
            pl.execute()
            redis_conn.hincrby('carts_%s' % user.id, sku_id, count)
            #         set 集合
            redis_conn.sadd('selected_%s' % user.id, sku_id)
            #     4.3 返回
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})
        else:

            # 5.未登录用户保存在cookie中
            """
            carts:{
                sku_id:{count:xxx,selected:xxx}
            }
            """
            #     5.1 先读取ｃｏｏｋｉｅ数据，判断ｃｏｏｋｉｅ数据中，
            # 是否存在ｃａｒｔｓ数据
            carts = request.COOKIES.get('carts')
            if carts is not None:
                # 若存在，则对数据进行解密
                # 先将ｂａｓｅ６４　数据进行解密为ｂｙｔｅｓ类型
                decode = base64.b64decode(carts)
                # 再将ｂｙｔｅｓ类型数据转化为字典
                cookie_cart = pickle.loads(decode)

            else:
                # 如果不存在，则初始化字典，
                cookie_cart = {}
            # 判断ｓｋｕ_id是否存在与ｃｏｏｋｉｅ_cart
            if sku_id in cookie_cart:
                # 先把原数量获取到
                orginal_count = cookie_cart[sku_id]['count']
                # 再累加
                count += orginal_count

            # 再更新数据　
            cookie_cart[sku_id]={
                'count':count,
                'selected':selected,
            }
            #     5.2 加密
            # 5.2.1将字典转成ｂｙｔｅｓ类型
            dumps = pickle.dumps(cookie_cart)
            # 5.2.2将ｂｙｔｅｓ类型进行ｂａｓｅ６４加密
            cookie_data = base64.b64encode(dumps)
            #     5.3 设置cookie
            response = http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})

            response.set_cookie('carts',cookie_data.decode(),max_age=3600)
            #     5.4 返回相应
            return response

    """
    前端根据用户状态，登陆就传递用户信息，不登陆就不传用户信息

    # １．判断用户是否登陆
    # ２．登陆用户到ｒｅｄｉｓ中获取数据
    #     ２．１连接ｒｅｄｉｓ
    #     ２．２获取数据
    #
    #
    # ３．未登陆用户到ｃｏｏｋｉｅ中获取数据
    #     ３．１获取ｃｏｏｋｉｅ中ｃａｒｔｓ数据，同时进行判断
    #     ３．２ｃａｒｔｓ：｛ｓｋｕ_id:{count:xxx,selected:xxx}｝
    # 抽取
    # ４．获取所有商品ｉｄ
    # ５．根据商品ｉｄ查询商品详细信息
    # ６．就爱那个对象转换成字典的
    # ７．返回响应
    """
    # 展示购物车
    def get(self,request):
        # １．判断用户是否登陆
        user = request.user
        if user.is_authenticated:

            # ２．登陆用户到ｒｅｄｉｓ中获取数据
            #     ２．１连接ｒｅｄｉｓ
            # 最好用管道
            redis_conn = get_redis_connection('carts')
            #     ２．２redis获取数据hash  carts_userid:{sku_id:count}
            sku_id_count = redis_conn.hgetall('carts_%s'%user.id)
            # set 数据
            selected_ids = redis_conn.smembers('selected_%s'%user.id)
            # 因为ｒｅｄｉｓ和ｃｏｏｋｉｅ的数据格式不一致，需要转换数据
            # 将ｒｅｄｉｓ转换成ｃｏｏｋｉｅ格式
            # carts:{sku_id:{count:xxx,selected:xxx}}

            cookie_cart = {}

            for sku_id,count in sku_id_count.items():
                # 判断遍历的商品ｉｄ是否在选中的列表中
                if sku_id in selected_ids:
                    selected = True
                else:
                    selected = False

                cookie_cart[int(sku_id)]={
                    'count':int(count),
                    # 'selected':sku_id in selected_ids,
                    'selected':selected,
                }
                pass
        else:
            # ３．未登陆用户到ｃｏｏｋｉｅ中获取数据
            carts = request.COOKIES.get('carts')
            #     ３．１获取ｃｏｏｋｉｅ中ｃａｒｔｓ数据，同时进行判断
            if carts is not None:
                # 有数据
                decode = base64.b64decode(carts)
                cookie_cart = pickle.loads(decode)
            else:
                # 没有数据
                cookie_cart={}

            #  carts:{sku_id:{count:xxx,selected:xxx}}
            pass
        # ４．获取所有商品ｉｄ
        ids = cookie_cart.keys()
        # ５．根据商品ｉｄ查询商品详细信息
        # mysql:decimal(货币类型)
        skus=[]
        for id in ids:
            sku = SKU.objects.get(pk=id)
            # ６．将对象转换成字典的
            skus.append({
                'id': sku.id,
                'name': sku.name,
                # redis 获取的数据是bytes类型，需要类型转换成int（sku_id,count）否则get不到
                'count': cookie_cart.get(sku.id).get('count'),
                'selected': str(cookie_cart.get(sku.id).get('selected')),  # 将True，转'True'，方便json解析
                'default_image_url': sku.default_image.url,
                'price': str(sku.price),  # 从Decimal('10.2')中取出'10.2'，方便json解析
                'amount': str(sku.price * cookie_cart.get(sku.id).get('count')),
            })
        context = {
            'cart_skus':skus,
        }
        # ７．返回响应
        return render(request,'cart.html',context)

    """
    # 1.接收数据
    # 2.验证数据
    # 3.验证用户信息，根据用户信息进行判断
    # 4.登陆用户redis
    # 5.未登陆用户cookie

    # 1.接收数据
    # 2.验证数据
    #     2.0sku_id,selected,count都要提交过来
    #     2.1验证商品ｉｄ
    #     2.2验证商品数量
    #     2.3选中状态是否为bool
    # 3.验证用户信息，根据用户信息进行判断
    # 4.登陆用户redis
    #     4.1连接redis
    #     4.2更新数据
    #     4.3返回响应
    # 5.未登陆用户cookie
    #     5.1获取cookie中的carts数据
    #     5.2判断数据是否存在
    #     5.3更新数据
    #     5.4加密处理
    #     5.5返回响应
    """
    # 修改购物车

    def put(self,request):
        # 1.后端接收数据
        data = json.loads(request.body.decode())
        # 2.验证数据
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)
        # 2.1商品ｉｄ和个数必须传递
        if not all([sku_id, count,selected]):
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数不全'})
        # 2.2判断商品是否存在
        try:
            sku = SKU.objects.get(pk=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({'code': RETCODE.NODATAERR, 'errmsg': '没有此商品'})
        # 2.3判断商品个数是否为整形
        try:
            count = int(count)
        except Exception as e:
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数错误'})
        # 2.4判断选中状态是否为布尔值
        if not isinstance(selected, bool):
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数错误'})
        # 3.判断用户登陆状态
        user = request.user
        if user.is_authenticated:
            # 4.登陆用户redis
            #     4.1连接redis
            redis_conn = get_redis_connection('carts')
            #     4.2更新数据
            # hash
            redis_conn.hset('carts_%s'%user.id,sku_id,count)
            # set
            if selected:
                redis_conn.sadd('selected_%s'%user.id,sku_id)
            else:
                redis_conn.srem('selected_%s'%user.id,sku_id)
            #     4.3返回响应
            # 创建响应对象
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'amount': sku.price * count,
            }
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'cart_sku': cart_sku})
        else:
            # 5.未登陆用户cookie
            #     5.1获取cookie中的carts数据
            carts = request.COOKIES.get('carts')
            #     5.2判断数据是否存在
            if carts is not None:
                # 存在，解密
                cookie_cart = pickle.loads(base64.b64decode(carts))
            else:
                # 不存在
                cookie_cart={}
            #     5.3更新数据
            # carts: {sku_id: {count: xxx, selected: xxx}}
            if sku_id in cookie_cart:
                cookie_cart[sku_id]={
                    'count':count,
                    'selected':selected,
                }
                #     5.4加密处理
                cookie_data = base64.b64encode(pickle.dumps(cookie_cart))
            # 5.返回响应
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'amount': sku.price * count,
            }
            respone = http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'cart_sku': cart_sku})

            respone.set_cookie('carts',cookie_data.decode(),3600)

            return respone

    """
    # 1.接收数据
    # 2.验证数据
    # 3.判断用户登陆状态
    # 4.登陆用户保存在redis
    #     4.1 连接redis
    #     4.2 删除数据
    #     4.3 返回
    # 5.未登录用户操作cookie
    #     5.1 获取数据
    #     5.2判断数据是否存在
    #     5.3 删除数据
    #     5.4对最新的数据进行加密处理
    #   　5.5返回相应

    """
    # 删除购物车
    def delete(self,request):
        # 1.接收数据
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        # 2.验证数据(验证商品是否存在)
        try:
            sku=SKU .objects.get(pk=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({'code':RETCODE.NODATAERR,'errmsg':'无此数据'})
        # 3.判断用户登陆状态
        user = request.user
        if user.is_authenticated:
            ## 4.登陆用户redis
            #     4.1连接redis
            redis_conn = get_redis_connection('carts')
            #     4.2 删除数据
            # hash
            redis_conn.hdel('carts_%s'%user.id,sku_id)
            # set
            redis_conn.srem('selected_%s'%user.id,sku_id)
            #     4.3 返回响应
            return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})
        else:
            #     5.1获取cookie中的carts数据
            carts = request.COOKIES.get('carts')
            #     5.2判断数据是否存在
            if carts is not None:
                # 存在，解密
                cookie_cart = pickle.loads(base64.b64decode(carts))
            else:
                # 不存在
                cookie_cart = {}
            #     5.3 删除数据
            if sku_id in cookie_cart:
                del cookie_cart[sku_id]
            #     5.4对最新的数据进行加密处理
            cookie_data = base64.b64encode(pickle.dumps(cookie_cart))
            #   　5.5返回相应
            response = http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})

            response.set_cookie('carts',cookie_data,3600)

            return response

# 全选购物车

class CartsSelectAllView(View):
    """全选购物车"""

    def put(self, request):
        # 接收参数
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get('selected', True)

        # 校验参数
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseBadRequest('参数selected有误')

        # 判断用户是否登录
        user = request.user
        if user.is_authenticated:
            # 用户已登录，操作redis购物车
            # 用户已登录，操作redis购物车
            redis_conn = get_redis_connection('carts')
            cart = redis_conn.hgetall('carts_%s' % user.id)
            sku_id_list = cart.keys()
            if selected:
                # 全选
                redis_conn.sadd('selected_%s' % user.id, *sku_id_list)
            else:
                # 取消全选
                redis_conn.srem('selected_%s' % user.id, *sku_id_list)
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '全选购物车成功'})

        else:
            # 用户未登录，操作cookie购物车
            cart = request.COOKIES.get('carts')
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '全选购物车成功'})
            if cart is not None:
                cart = pickle.loads(base64.b64decode(cart.encode()))
                for sku_id in cart:
                    cart[sku_id]['selected'] = selected
                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('carts', cookie_cart, 3600)

            return response



